home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / xbmc-9.11.exe / scripts / AppleMovieTrailers / resources / plugins / Apple Movie Trailers / amtAPI / xbmcplugin_player.py < prev    next >
Encoding:
Python Source  |  2009-04-04  |  12.2 KB  |  243 lines

  1. """
  2.     Player module: downloads then plays trailers
  3. """
  4.  
  5. # TODO: remove this when dialog issue is resolved
  6. import xbmc
  7. # set our title
  8. g_title = unicode( xbmc.getInfoLabel( "ListItem.Title" ), "utf-8" )
  9. # set our studio (only works if the user is using the video library)
  10. g_studio = unicode( xbmc.getInfoLabel( "ListItem.Studio" ), "utf-8" )
  11. # set our genre (only works if the user is using the video library)
  12. g_genre = unicode( xbmc.getInfoLabel( "ListItem.Genre" ), "utf-8" )
  13. # set our rating (only works if the user is using the video library)
  14. g_mpaa_rating = xbmc.getInfoLabel( "ListItem.MPAA" )
  15. # set our thumbnail
  16. g_thumbnail = xbmc.getInfoImage( "ListItem.Thumb" )
  17. # set our plotoutline
  18. g_plotoutline = unicode( xbmc.getInfoLabel( "ListItem.PlotOutline" ), "utf-8" )
  19. # set our released date
  20. g_releasedate = xbmc.getInfoLabel( "ListItem.Property(releasedate)" )
  21. # set our year
  22. g_year = 0
  23. if ( xbmc.getInfoLabel( "ListItem.Year" ) ):
  24.     g_year = int( xbmc.getInfoLabel( "ListItem.Year" ) )
  25.  
  26. # create the progress dialog (we do it here so there is minimal delay with nothing displayed)
  27. import xbmcgui
  28. pDialog = xbmcgui.DialogProgress()
  29. pDialog.create( g_title, xbmc.getLocalizedString( 30503 ) )
  30.  
  31. # main imports
  32. import sys
  33. import os
  34. import xbmcplugin
  35.  
  36. import urllib
  37.  
  38.  
  39. class _Info:
  40.     def __init__( self, *args, **kwargs ):
  41.         self.__dict__.update( kwargs )
  42.  
  43.  
  44. class Main:
  45.     # base paths
  46.     BASE_CACHE_PATH = os.path.join( xbmc.translatePath( "special://profile" ), "Thumbnails", "Video" )
  47.  
  48.     def __init__( self ):
  49.         self._get_settings()
  50.         # parse argv for our trailer url and movie id
  51.         self._parse_argv()
  52.         # split trailer_url into separate videos
  53.         urls = self.args.trailer_url.replace( "stack://", "" ).split( " , " ) 
  54.         # do we need to download the videos
  55.         if ( self.settings[ "mode" ] > 0 ):
  56.             # download the video
  57.             urls = self._download_video()
  58.         # play the video
  59.         self._play_video( urls )
  60.  
  61.     def _parse_argv( self ):
  62.         # call _Info() with our formatted argv to create the self.args object
  63.         exec "self.args = _Info(%s)" % ( sys.argv[ 2 ][ 1 : ].replace( "&", ", " ).replace( "\\u0027", "'" ).replace( "\\u0022", '"' ).replace( "\\u0026", "&" ), )
  64.  
  65.     def _get_settings( self ):
  66.         self.settings = {}
  67.         self.settings[ "mode" ] = int( xbmcplugin.getSetting( "mode" ) )
  68.         self.settings[ "download_path" ] = xbmcplugin.getSetting( "download_path" )
  69.         self.settings[ "mark_watched" ] = xbmcplugin.getSetting( "mark_watched" ) == "true"
  70.         self.settings[ "amt_db_path" ] = xbmc.translatePath( xbmcplugin.getSetting( "amt_db_path" ) )
  71.         ##self.settings[ "player_core" ] = ( xbmc.PLAYER_CORE_MPLAYER, xbmc.PLAYER_CORE_DVDPLAYER, )[ int( xbmcplugin.getSetting( "player_core" ) ) ]
  72.  
  73.     def _download_video( self ):
  74.         try:
  75.             urls = self.args.trailer_url.replace( "stack://", "" ).split( " , " ) 
  76.             # TODO: No longer needed as we sort in the videos module **** remove after testing
  77.             #urls.sort()
  78.             filepaths = []
  79.             for count, url in enumerate( urls ):
  80.                 title = g_title
  81.                 # construct an xbox compatible filepath
  82.                 ext = os.path.splitext( url )[ 1 ]
  83.                 # we need to keep the end of the title if more than one trailer
  84.                 multiple = len( urls ) > 1
  85.                 # split and insert the trailer number if more than one
  86.                 filepath = "%s%s" % ( title, ( "", "_%d" % ( count + 1, ), )[ multiple ], )
  87.                 # folder to save to
  88.                 dirname = "Z:/"
  89.                 if ( not self.settings[ "download_path" ].startswith( "smb://" ) ):
  90.                     dirname = self.settings[ "download_path" ]
  91.                 # get a valid filepath
  92.                 filepath = self._make_legal_filepath( os.path.join( dirname, filepath + ext ), save_end=multiple )
  93.                 # if the file does not exist, download it
  94.                 if ( os.path.isfile( os.path.join( self.settings[ "download_path" ], os.path.basename( filepath ) ) ) ):
  95.                     filepath = os.path.join( self.settings[ "download_path" ], os.path.basename( filepath ) )
  96.                 else:
  97.                     if ( self.settings[ "mode" ] == 1 ):
  98.                         filepath = "Z:/AMT_Video_%d%s" % ( count, ext, )
  99.                     # set our display message
  100.                     self.msg = "%s %d of %d" % ( xbmc.getLocalizedString( 30500 ), count + 1, len( urls ), )
  101.                     # fetch the video
  102.                     urllib.urlretrieve( url, filepath, self._report_hook )
  103.                     # make the conf file and copy to smb share if necessary
  104.                     filepath = self._make_conf_file( filepath )
  105.                 filepaths += [ filepath ]
  106.         except:
  107.             if ( os.path.isfile( filepath ) ):
  108.                 os.remove( filepath )
  109.             filepaths = []
  110.             pDialog.close()
  111.         return filepaths
  112.  
  113.     def _report_hook( self, count, blocksize, totalsize ):
  114.         percent = int( float( count * blocksize * 100) / totalsize )
  115.         pDialog.update( percent, self.msg )
  116.         if ( pDialog.iscanceled() ): raise
  117.  
  118.     def _make_legal_filepath( self, path, compatible=False, extension=True, conf=True, save_end=False ):
  119.         # xbox, win32 and linux have different filenaming requirements
  120.         environment = os.environ.get( "OS", "xbox" )
  121.         # first we normalize the path (win32 and xbox support / as path separators)
  122.         if ( environment == "win32" or environment == "xbox" ):
  123.             path = path.replace( "\\", "/" )
  124.         # split our drive letter
  125.         drive, tail = os.path.splitdrive( path )
  126.         # split the rest of the path
  127.         parts = tail.split( "/" )
  128.         # if this is a linux path and compatible is true set the drive
  129.         if ( not drive and parts[ 0 ].endswith( ":" ) and len( parts[ 0 ] ) == 2 and compatible ):
  130.             drive = parts[ 0 ]
  131.             parts[ 0 ] = ""
  132.         # here is where we make the filepath valid
  133.         if ( environment == "xbox" or environment == "win32" or compatible ):
  134.             # win32 and xbox invalid characters
  135.             illegal_characters = """,*=|<>?;:"+"""
  136.             # enumerate through and make each part valid
  137.             for count, part in enumerate( parts ):
  138.                 tmp_name = ""
  139.                 for char in part:
  140.                     # if char's ord() value is > 127 or an illegal character remove it
  141.                     if ( char in illegal_characters or ord( char ) > 127 ): char = ""
  142.                     tmp_name += char
  143.                 if ( environment == "xbox" or compatible ):
  144.                     # we need to trim the part if it's larger than 42, we need to account for ".conf"
  145.                     if ( len( tmp_name ) > 42 - ( conf * 5 ) ):
  146.                         # special handling of the last part with extension
  147.                         if ( count == len( parts ) - 1 and extension == True ):
  148.                             # split the part into filename and extention
  149.                             filename, ext = os.path.splitext( tmp_name )
  150.                             # do we need to save the last two characters of the part for file number (eg _1, _2...)
  151.                             if ( save_end ):
  152.                                 tmp_name = filename[ : 35 - len( ext ) ] + filename[ -2 : ]
  153.                             else:
  154.                                 tmp_name = filename[ : 37 - len( ext ) ]
  155.                             tmp_name = "%s%s" % ( tmp_name.strip(), ext )
  156.                         # not the last part so just trim the length
  157.                         else:
  158.                             tmp_name = tmp_name[ : 42 ].strip()
  159.                 # add our validated part to our list
  160.                 parts[ count ] = tmp_name
  161.         # join the parts into a valid path, we use forward slash to remain os neutral
  162.         filepath = drive + "/".join( parts )
  163.         # win32 needs to be encoded to utf-8
  164.         if ( environment == "win32" ):
  165.             return filepath.encode( "utf-8" )
  166.         else:
  167.             return filepath
  168.  
  169.     def _make_conf_file( self, filepath ):
  170.         try:
  171.             new_filepath = filepath
  172.             # create conf file for better MPlayer playback
  173.             if ( not os.path.isfile( filepath + ".conf" ) ):
  174.                 f = open( filepath + ".conf" , "w" )
  175.                 f.write( "nocache=1" )
  176.                 f.close()
  177.             # if save location is a samba share, copy the file
  178.             if ( self.settings[ "download_path" ].startswith( "smb://" ) ):
  179.                 new_filepath = os.path.join( self.settings[ "download_path" ], os.path.basename( filepath ) )
  180.                 new_thumbpath = os.path.join( self.settings[ "download_path" ], os.path.splitext( os.path.basename( filepath ) )[ 0 ] + ".tbn" )
  181.                 xbmc.executehttpapi("FileCopy(%s,%s)" % ( filepath, new_filepath, ) )
  182.                 xbmc.executehttpapi("FileCopy(%s,%s)" % ( g_thumbnail, new_thumbpath, ) )
  183.         except:
  184.             # oops print error message
  185.             print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  186.         return new_filepath
  187.  
  188.  
  189.     def _play_video( self, filepaths ):
  190.         if ( filepaths ):
  191.             # set the thumbnail
  192.             thumbnail = g_thumbnail
  193.             # set the default icon
  194.             icon = "DefaultVideo.png"
  195.             # create our playlist
  196.             playlist = xbmc.PlayList( xbmc.PLAYLIST_VIDEO )
  197.             # clear any possible entries
  198.             playlist.clear()
  199.             # enumerate thru and add our item
  200.             for count, filepath in enumerate( filepaths ):
  201.                 # only need to add label, icon and thumbnail, setInfo() and addSortMethod() takes care of label2
  202.                 listitem = xbmcgui.ListItem( g_title, iconImage=icon, thumbnailImage=thumbnail )
  203.                 # set the key information
  204.                 listitem.setInfo( "video", { "Title": "%s%s" % ( g_title, ( "", " (%s %d)" % ( xbmc.getLocalizedString( 30504 ), count + 1, ) )[ len( filepaths ) > 1 ], ), "Genre": g_genre, "Studio": g_studio, "Plot": g_plotoutline, "PlotOutline": g_plotoutline, "Year": g_year } )
  205.                 # set release date property
  206.                 listitem.setProperty( "releasedate", g_releasedate )
  207.                 # add our item
  208.                 playlist.add( filepath, listitem )
  209.             # mark the video watched
  210.             if ( self.settings[ "mark_watched" ] ):
  211.                 self._mark_watched()
  212.             # we're finished
  213.             pDialog.close()
  214.             # play the playlist (TODO: when playlist can set the player core, add this back in)
  215.             xbmc.Player().play( playlist )#self.settings[ "player_core" ]
  216.  
  217.     def _mark_watched( self ):
  218.         try:
  219.             pDialog.update( -1, xbmc.getLocalizedString( 30502 ), xbmc.getLocalizedString( 30503 ) )
  220.             from pysqlite2 import dbapi2 as sqlite
  221.             import datetime
  222.             fetch_sql = "SELECT times_watched FROM movies WHERE idMovie=?;"
  223.             update_sql = "UPDATE movies SET times_watched=?, last_watched=? WHERE idMovie=?;"
  224.             # connect to the database
  225.             db = sqlite.connect( self.settings[ "amt_db_path" ] )
  226.             # get our cursor object
  227.             cursor = db.cursor()
  228.             # we fetch the times watched so we can increment by one
  229.             cursor.execute( fetch_sql, ( self.args.idMovie, ) )
  230.             # increment the times watched
  231.             times_watched = cursor.fetchone()[ 0 ] + 1
  232.             # get todays date
  233.             last_watched = datetime.date.today()
  234.             # update the record with our new values
  235.             cursor.execute( update_sql, ( times_watched, last_watched, self.args.idMovie, ) )
  236.             # commit the update
  237.             db.commit()
  238.             # close the database
  239.             db.close()
  240.         except:
  241.             # oops print error message
  242.             print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  243.